/**
    @file portal_debug.cpp
    @brief Debug rendering for PCZSceneManager
*/

#include "portal_debug.hpp"

template<> pm3::dbg::PORTAL_DRAWER* Ogre::Singleton<pm3::dbg::PORTAL_DRAWER>::ms_Singleton = 0;
pm3::dbg::PORTAL_DRAWER pm3::dbg::g_portal_drawer;

pm3::dbg::PORTAL_DRAWER::PORTAL_DRAWER() {
    m_debug = false;
    m_line_drawer = NULL;
}

pm3::dbg::PORTAL_DRAWER::~PORTAL_DRAWER() {
//    Ogre::MaterialManager::getSingleton().remove( "Portals/DebugLines" );
//    Ogre::ResourceGroupManager::getSingleton().destroyResourceGroup( "Portals" );
    m_debug = false;
    m_line_drawer = NULL;
}

void pm3::dbg::PORTAL_DRAWER::init( Ogre::SceneNode *p_node ) {
    pm3::LOGGER *log = pm3::LOGGER::getSingletonPtr();

    //! \bug init is called twice
    if (!m_line_drawer) {
	    m_line_drawer = new BtOgre::DynamicLines( Ogre::RenderOperation::OT_LINE_LIST );

        m_node = p_node;
        //! \todo Detach from any previous nodes
        m_node->attachObject( m_line_drawer );

        Ogre::ResourceGroupManager::getSingleton().createResourceGroup( "Portals" );
        Ogre::MaterialPtr mat = Ogre::MaterialManager::getSingleton().create( "Portals/DebugLines", "Portals" );
        mat->setReceiveShadows( false );
        mat->setSelfIllumination( 1, 1, 0 );

        m_line_drawer->setMaterial( "Portals/DebugLines" );

//        m_debug = true;

        if (log)
            log->report( "Pixel", "I: Portal drawer initialized\n" );
    }
}

void pm3::dbg::PORTAL_DRAWER::step() {
    if (!m_line_drawer)
        return;

    if (m_debug) {
	    m_line_drawer->update();
	    m_node->needUpdate();
	    m_line_drawer->clear();
    } else {
	    m_line_drawer->clear();
	    m_line_drawer->update();
	    m_node->needUpdate();
    }
}

void pm3::dbg::PORTAL_DRAWER::drawPortal( Ogre::Portal *p_portal ) {
    if (!m_line_drawer)
        return;

    if (p_portal) {
        switch (p_portal->getType()) {
            case Ogre::PortalBase::PORTAL_TYPE_QUAD:
                m_line_drawer->addPoint( p_portal->getDerivedCorner( 0 ) );
                m_line_drawer->addPoint( p_portal->getDerivedCorner( 1 ) );

                m_line_drawer->addPoint( p_portal->getDerivedCorner( 1 ) );
                m_line_drawer->addPoint( p_portal->getDerivedCorner( 2 ) );

                m_line_drawer->addPoint( p_portal->getDerivedCorner( 2 ) );
                m_line_drawer->addPoint( p_portal->getDerivedCorner( 3 ) );

                m_line_drawer->addPoint( p_portal->getDerivedCorner( 3 ) );
                m_line_drawer->addPoint( p_portal->getDerivedCorner( 0 ) );

                m_line_drawer->addPoint( p_portal->getDerivedCorner( 0 ) );
                m_line_drawer->addPoint( p_portal->getDerivedCorner( 2 ) );
                break;
            //! \todo Support for other portal types
            default: break;
        }
    }
}

void pm3::dbg::PORTAL_DRAWER::drawNode( Ogre::SceneNode *p_node ) {
    Ogre::AxisAlignedBox aabb;

    if (!m_line_drawer)
        return;

    if (p_node) {
        aabb = p_node->_getWorldAABB();

        m_line_drawer->addPoint( aabb.getMinimum() );
        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMaximum().x, aabb.getMinimum().y, aabb.getMinimum().z ) );

        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMaximum().x, aabb.getMinimum().y, aabb.getMinimum().z ) );
        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMaximum().x, aabb.getMaximum().y, aabb.getMinimum().z ) );

        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMaximum().x, aabb.getMaximum().y, aabb.getMinimum().z ) );
        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMinimum().x, aabb.getMaximum().y, aabb.getMinimum().z ) );

        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMinimum().x, aabb.getMaximum().y, aabb.getMinimum().z ) );
        m_line_drawer->addPoint( aabb.getMinimum() );

        m_line_drawer->addPoint( aabb.getMaximum() );
        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMaximum().x, aabb.getMinimum().y, aabb.getMaximum().z ) );

        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMaximum().x, aabb.getMinimum().y, aabb.getMaximum().z ) );
        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMinimum().x, aabb.getMinimum().y, aabb.getMaximum().z ) );

        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMinimum().x, aabb.getMinimum().y, aabb.getMaximum().z ) );
        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMinimum().x, aabb.getMaximum().y, aabb.getMaximum().z ) );

        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMinimum().x, aabb.getMaximum().y, aabb.getMaximum().z ) );
        m_line_drawer->addPoint( aabb.getMaximum() );

        m_line_drawer->addPoint( aabb.getMaximum() );
        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMaximum().x, aabb.getMaximum().y, aabb.getMinimum().z ) );

        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMinimum().x, aabb.getMinimum().y, aabb.getMaximum().z ) );
        m_line_drawer->addPoint( aabb.getMinimum() );

        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMinimum().x, aabb.getMaximum().y, aabb.getMaximum().z ) );
        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMinimum().x, aabb.getMaximum().y, aabb.getMinimum().z ) );

        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMaximum().x, aabb.getMinimum().y, aabb.getMaximum().z ) );
        m_line_drawer->addPoint( Ogre::Vector3( aabb.getMaximum().x, aabb.getMinimum().y, aabb.getMinimum().z ) );
    }
}

void pm3::dbg::PORTAL_DRAWER::set_enabled( bool b_on ) {
    if (!m_line_drawer)
        return;

    m_debug = b_on;

    if (!m_debug)
	    m_line_drawer->clear();
}

